package render.display
{
	import flash.display.Stage;
	import flash.display3D.Context3D;
	import flash.display3D.Context3DProgramType;
	import flash.display3D.Context3DVertexBufferFormat;
	import flash.display3D.Program3D;
	import flash.geom.Matrix3D;
	import flash.geom.Vector3D;
	
	import render.RenderManager;
	import render.materials.shaders.Shader2D;
	import render.materials.textures.Texture2D;

	public class RenderDisplayObject extends RenderObject
	{
		protected var _shader2D:Shader2D;
		
		public static const DEFAULT_INDEX_DATA:Vector.<uint> = Vector.<uint>([0,1,2,0,2,3]);
		public static const DEFAULT_VERTEX_DATA:Vector.<Number> = Vector.<Number>([
			-0.5 ,  0.5 , 	0,		0 ,	1,     	
			-0.5 , -0.5 , 	0,		0 ,	0,			
			0.5 , -0.5 , 	0,		1 ,	0,			
			0.5 ,  0.5 , 	0,		1 ,	1 
		]);
		protected const DEFAULT_VERTEX_SHADER:String =
			"m44 op, va0, vc0   \n" +
			"mov v0, va1		\n"+
			"mov v1, va1\n";
		
		protected const DEFAULT_FRAGMENT_SHADER:String =
			"mov ft0, v0\n"+
			"tex ft0, v0, fs0 <2d,nomip,linear>\n"+
			"mov oc, ft0\n";
		
		public function RenderDisplayObject(stage:Stage, context3D:Context3D, program3D:Program3D, width:Number=1, height:Number=1, x:Number=0, y:Number=0, texture2D:Texture2D=null)
		{
			_stage=stage;
			_context3D=context3D;
			_program3D=program3D;
			_width=width;
			_height=height;
			_x=x;
			_y=y;
			_texture2D=texture2D;
			
			setVertexBuffer(DEFAULT_VERTEX_DATA, 4, 0, 5);
			setIndexBuffer(DEFAULT_INDEX_DATA, 6, 0, 6);
			_shader2D=RenderManager.instance.createShader(_context3D, _program3D, DEFAULT_VERTEX_SHADER, DEFAULT_FRAGMENT_SHADER);
			_context3D.setVertexBufferAt(0,vertexBuffer3D, 0, Context3DVertexBufferFormat.FLOAT_3);
			_context3D.setVertexBufferAt(1,vertexBuffer3D, 3, Context3DVertexBufferFormat.FLOAT_2);
		}
		
		protected function setVertexBuffer(data:Vector.<Number>, numVertices:uint=3, startVertices:uint=0, element:uint=3):void
		{
			_vertexBuffer3D = _context3D.createVertexBuffer(numVertices, element)			
			_vertexBuffer3D.uploadFromVector(data, startVertices, numVertices )
		}
		
		protected function setIndexBuffer(data:Vector.<uint>, numIndices:uint, startOffset:uint, count:uint):void
		{
			_indexBuffer3D = _context3D.createIndexBuffer(numIndices)			
			_indexBuffer3D.uploadFromVector(data, startOffset, count)			
		}
		
		protected function setLocalMatrix():void
		{			
			_localMatrix.identity()
			_localMatrix.appendRotation(rotation, Vector3D.Z_AXIS)
			_localMatrix.appendScale(width * (_scaleX), -height * (_scaleY), 1);			
			_localMatrix.appendTranslation(-_stage.stageWidth/2+x, _stage.stageHeight/2-y, 0);		
			_localMatrix.append(makeOrthoProjection(_stage.stageWidth, _stage.stageHeight));
		}
		
		protected function makeOrthoProjection(w:Number, h:Number):Matrix3D
		{
			return new Matrix3D(Vector.<Number>
				([
					2/w, 0  ,       0,        0,
					0  , 2/h,       0,        0,
					0  , 0  ,       1,        1,
					0  , 0  ,       0,        1
				]));
		}
		
		protected function setTexture2D():void
		{
			if(_texture2D)
			{
				_context3D.setTextureAt(0, _texture2D.texture);
			}
		}
		
		override public function render():void
		{
			super.render();
			setTexture2D();
			setLocalMatrix();
			_context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _localMatrix, true)
			_context3D.drawTriangles(_indexBuffer3D, 0, 2);
		}
		
		override public function dispose():void
		{
			if(_shader2D)
			{
				_shader2D.dispose();
				_shader2D=null;
			}
			super.dispose();
		}
	}
}